package com.alex.jvm.reference;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;

/**
 * 设置堆最大大小: -Xmx:20m
 * 打印GC详情: -XX:+PrintGCDetails -verbose:gc
 *
 * jvm参数设置: -Xmx20m -XX:+PrintGCDetails -verbose:gc
 *
 * <p>
 * 使用软引用, 在内存敏感的程序中, 保证程序不会OOM.
 * eg: 加载图片或者其它资源时, 使用软引用包含资源, 这样使用完成之后,
 * 若内存不足的时候, 可以被GC回收, 而不会因为在存活区域内, 导致, GC无法回收不再使用的资源.
 */
public class SoftReferenceDemo1 {

    private static final int FILE_SIZE = 1024 * 1024 * 4; // 4M

    public static void main(String[] args) {
        // StrongReference(); //资源会一直被强引用, 无法回收.
         softReference(); // 内存不足时, 会回收软引用的数据.
//        softReferenceQueue(); // 从数据中, 清除掉无用的软引用, 保证数据集合中的数据一直有效.
    }

    private static void softReferenceQueue() {
        ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
        List<SoftReference<byte[]>> data = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            SoftReference<byte[]> softReference = new SoftReference<>(new byte[FILE_SIZE], referenceQueue);
            data.add(softReference); // 当超过堆大小的时候, 第一次GC之后, 若是内存还不足, 则回收SoftReference的数据.
            System.out.println("count: " + i);
        }

        System.out.println("=====移除无用的软引用==BEFORE===");
        Reference<? extends byte[]> poll = referenceQueue.poll();
        while (poll != null) {
            data.remove(poll);
            poll = referenceQueue.poll();
        }

        System.out.println("=====移除无用的软引用==AFTER===");
        for (int i = 0; i < data.size(); i++) {
            // 当后面去获取数据时, 因为已经被回收, 已经无法获取到GC之后存储的数据.
            System.out.println(data.get(i).get());
        }
    }

    private static void softReference() {
        List<SoftReference<byte[]>> data = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[FILE_SIZE]);
            data.add(softReference); // 当超过堆大小的时候, 第一次GC之后, 若是内存还不足, 则回收SoftReference的数据.
            System.out.println("count: " + i);
        }

        for (int i = 0; i < 5; i++) {
            // 当后面去获取数据时, 因为已经被回收, 已经无法获取到GC之后存储的数据.
            System.out.println(data.get(i).get());
        }
    }

    private static void StrongReference() {
        List<byte[]> data = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            data.add(new byte[FILE_SIZE]);
            System.out.println("count: " + i);
        }
    }
}


